package com.seed.codegenerator.manager.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.common.base.CaseFormat;
import com.seed.codegenerator.generator.config.GenConfig;
import com.seed.codegenerator.generator.entity.PageData;
import com.seed.codegenerator.generator.enums.CodeGeneratorEnum;
import com.seed.codegenerator.generator.system.SystemCodeGenerateOne;
import com.seed.codegenerator.generator.system.SystemCodeGenerateOneToMany;
import com.seed.codegenerator.manager.CodeGenerator;
import com.seed.codegenerator.manager.dto.GenerateDTO;
import com.seed.codegenerator.manager.form.GenerateLeftRightDictionaryForm;
import com.seed.core.pojo.dto.SeedMessageDTO;
import com.seed.core.table.DataBaseTableServiceI;
import com.seed.core.table.entity.DataBaseTable;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.online.cgform.entity.OnlCgformField;
import org.jeecg.modules.online.cgform.entity.OnlCgformHead;
import org.jeecg.modules.online.cgform.model.d;
import org.jeecg.modules.online.cgform.service.IOnlCgformFieldService;
import org.jeecg.modules.online.cgform.service.IOnlCgformHeadService;
import org.jeecgframework.codegenerate.generate.pojo.ColumnVo;
import org.jeecgframework.codegenerate.generate.pojo.TableVo;
import org.jeecgframework.codegenerate.generate.pojo.onetomany.MainTableVo;
import org.jeecgframework.codegenerate.generate.pojo.onetomany.SubTableVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;


/**
 * @author gchiaway
 * 日期: 2020-02-12
 * 时间: 21:36
 */
@Slf4j
@Service("codeGeneratorService")
public class CodeGeneratorImpl implements CodeGenerator {

    /**
     * 表辅助类
     */
    private final DataBaseTableServiceI dataBaseTableService;

    private final IOnlCgformHeadService onlCgformHeadService;

    private final IOnlCgformFieldService fieldService;

    /**
     * 生成配置文件
     */
    private final GenConfig genConfig;

    @Autowired
    public CodeGeneratorImpl(DataBaseTableServiceI dataBaseTableService,
                             GenConfig genConfig,
                             IOnlCgformHeadService onlCgformHeadService,
                             IOnlCgformFieldService fieldService) {
        this.dataBaseTableService = dataBaseTableService;
        this.genConfig = genConfig;
        this.onlCgformHeadService = onlCgformHeadService;
        this.fieldService = fieldService;
    }

    /**
     * 生成后台代码
     *
     * @param outFilePath 输出目录
     * @param tableNames  表名
     * @return 生成结果
     */
    @Override
    public GenerateDTO generateSystemCode(String outFilePath, String... tableNames) {
        return this.generateSystemCode(outFilePath, null, tableNames);
    }

    /**
     * 生成后台代码
     *
     * @param outFilePath       输出目录
     * @param codeGeneratorEnum 代码风格
     * @param tableNames        表名
     * @return 生成结果
     */
    @Override
    public GenerateDTO generateSystemCode(String outFilePath, CodeGeneratorEnum codeGeneratorEnum, String... tableNames) {
        GenerateDTO result = new GenerateDTO();
        if (StringUtils.isEmpty(codeGeneratorEnum)) {
            codeGeneratorEnum = CodeGeneratorEnum.MANY;
        }
        if (codeGeneratorEnum.equals(CodeGeneratorEnum.EMPTY) || codeGeneratorEnum.equals(CodeGeneratorEnum.ONE)) {
            codeGeneratorEnum = CodeGeneratorEnum.MANY;
        }
        for (String tableName : tableNames) {
            LambdaQueryWrapper<OnlCgformHead> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(OnlCgformHead::getTableName, tableName);
            d onlGenerateModel;
            HashMap<String, String> extendParams = new HashMap<>(16);
            try {
                OnlCgformHead onlCgformHead = onlCgformHeadService.getOne(queryWrapper);
                if (StringUtils.isEmpty(onlCgformHead)) {
                    result.error("表名信息异常");
                    return result;
                }
                List<DataBaseTable> dataBaseTableList = dataBaseTableService.listEntityNamesByTableNamesPrefix(onlCgformHead.getTableName());
                if (CollectionUtils.isEmpty(dataBaseTableList)) {
                    result.error("表名信息异常");
                    return result;
                }
                DataBaseTable dataBaseTable = dataBaseTableList.get(0);
                PageData pageData = new PageData(dataBaseTable, genConfig);
                extendParams.put("apiPackage", pageData.getApiPackage());
                extendParams.put("bussiPackage", pageData.getBussPackage());
                extendParams.put("author", pageData.getAuthor());
                extendParams.put("tablePrefix", pageData.getTablePrefix());
                onlGenerateModel = new d();
                onlGenerateModel.setProjectPath(outFilePath);
                onlGenerateModel.setPackageStyle("service");
                onlGenerateModel.setJformType(onlCgformHead.getTableType() + "");
                onlGenerateModel.setJspMode("one");
                onlGenerateModel.setCode(onlCgformHead.getId());
                onlGenerateModel.setTableName(onlCgformHead.getTableName());
                onlGenerateModel.setEntityName(dataBaseTable.getEntityNameHump());
                onlGenerateModel.setEntityPackage(dataBaseTable.getEntityPackage());
                onlGenerateModel.setFtlDescription(onlCgformHead.getTableTxt());
                if (onlCgformHead.getTableType() == 2) {
                    String subTableStr = onlCgformHead.getSubTableStr();
                    if (oConvertUtils.isNotEmpty(subTableStr)) {
                        ArrayList<OnlCgformHead> onlCgformHeadArrayList = new ArrayList<>();
                        String[] var6 = subTableStr.split(",");
                        String[] var7 = var6;
                        int var8 = var6.length;

                        for (int i = 0; i < var8; ++i) {
                            String var10 = var7[i];
                            LambdaQueryWrapper<OnlCgformHead> onlCgformHeadLambdaQueryWrapper = new LambdaQueryWrapper<>();
                            onlCgformHeadLambdaQueryWrapper.eq(OnlCgformHead::getTableName, var10);
                            OnlCgformHead var12 = this.onlCgformHeadService.getOne(onlCgformHeadLambdaQueryWrapper);
                            onlCgformHeadArrayList.add(var12);
                        }

                        onlCgformHeadArrayList.sort((var1, var2) -> {
                            Integer var3 = var1.getTabOrderNum();
                            if (var3 == null) {
                                var3 = 0;
                            }
                            Integer var41 = var2.getTabOrderNum();
                            if (var41 == null) {
                                var41 = 0;
                            }
                            return var3.compareTo(var41);
                        });
                        List<d> subList = new ArrayList<>();
                        for (OnlCgformHead cgformHead : onlCgformHeadArrayList) {
                            List<DataBaseTable> subDataBaseTableList = dataBaseTableService.listEntityNamesByTableNamesPrefix(cgformHead.getTableName());
                            if (CollectionUtils.isEmpty(subDataBaseTableList)) {
                                result.error("表名信息异常");
                                return result;
                            }
                            DataBaseTable subDataBaseTable = subDataBaseTableList.get(0);
                            d subOnlGenerateModel = new d();
                            subOnlGenerateModel.setTableName(cgformHead.getTableName());
                            subOnlGenerateModel.setEntityName(subDataBaseTable.getEntityNameHump());
                            subOnlGenerateModel.setFtlDescription(cgformHead.getTableTxt());
                            subOnlGenerateModel.setCode(cgformHead.getId());
                            subList.add(subOnlGenerateModel);
                        }
                        onlGenerateModel.setSubList(subList);
                    }
                }
            } catch (Exception e) {
                result.error("表名信息异常");
                return result;
            }

            try {
                if ("1".equals(onlGenerateModel.getJformType())) {
                    this.generateCode(onlGenerateModel, CodeGeneratorEnum.ONE, extendParams);
                } else {
                    this.generateOneToMany(onlGenerateModel, codeGeneratorEnum, extendParams);
                }
            } catch (Exception e) {
                result.error("失败");
                return result;
            }
        }
        return result;
    }

    /**
     * 生成后台代码
     *
     * @param outFilePath 输出目录
     * @param form        左右字典表单
     * @return 生成结果
     */
    @Override
    public GenerateDTO generateLeftRightDictionaryCode(String outFilePath, GenerateLeftRightDictionaryForm form) {
        GenerateDTO result = new GenerateDTO();
        LambdaQueryWrapper<OnlCgformHead> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OnlCgformHead::getTableName, form.getTableName());
        d onlGenerateModel;
        HashMap<String, String> extendParams = new HashMap<>(16);
        try {
            OnlCgformHead onlCgformHead = onlCgformHeadService.getOne(queryWrapper);
            if (StringUtils.isEmpty(onlCgformHead)) {
                result.error("表名信息异常");
                return result;
            }
            List<DataBaseTable> dataBaseTableList = dataBaseTableService.listEntityNamesByTableNamesPrefix(onlCgformHead.getTableName());
            if (CollectionUtils.isEmpty(dataBaseTableList)) {
                result.error("表名信息异常");
                return result;
            }
            DataBaseTable dataBaseTable = dataBaseTableList.get(0);
            PageData pageData = new PageData(dataBaseTable, genConfig);
            extendParams.put("apiPackage", pageData.getApiPackage());
            extendParams.put("bussiPackage", pageData.getBussPackage());
            extendParams.put("author", pageData.getAuthor());
            extendParams.put("tablePrefix", pageData.getTablePrefix());
            extendParams.put("dictionaryName", form.getDictionaryName());
            if (form.getTableFieldName().contains("_")) {
                extendParams.put("tableFieldName", CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, form.getTableFieldName().toLowerCase()));
            } else {
                extendParams.put("tableFieldName", form.getTableFieldName());
            }
            onlGenerateModel = new d();
            onlGenerateModel.setProjectPath(outFilePath);
            onlGenerateModel.setPackageStyle("service");
            onlGenerateModel.setJformType(onlCgformHead.getTableType() + "");
            onlGenerateModel.setJspMode("one");
            onlGenerateModel.setCode(onlCgformHead.getId());
            onlGenerateModel.setTableName(onlCgformHead.getTableName());
            onlGenerateModel.setEntityName(dataBaseTable.getEntityNameHump());
            onlGenerateModel.setEntityPackage(dataBaseTable.getEntityPackage());
            onlGenerateModel.setFtlDescription(onlCgformHead.getTableTxt());
            if (!"1".equals(onlGenerateModel.getJformType())) {
                result.error("表类型异常!");
                return result;
            }
        } catch (Exception e) {
            result.error("表名信息异常");
            return result;
        }

        try {
            this.generateCode(onlGenerateModel, CodeGeneratorEnum.LEFT_RIGHT_DICTIONARY, extendParams);
        } catch (Exception e) {
            result.error("失败");
            return result;
        }
        return result;
    }

    /**
     * 生成空api代码
     *
     * @param outFilePath 输出目录
     * @param tableNames  表名
     * @return 生成结果
     */
    @Override
    public GenerateDTO generateEmptyCode(String outFilePath, String... tableNames) {
        GenerateDTO result = new GenerateDTO();
        for (String tableName : tableNames) {
            List<DataBaseTable> dataBaseTableList = dataBaseTableService.listEntityNamesByTableNamesPrefix(tableName);
            if (CollectionUtils.isEmpty(dataBaseTableList)) {
                result.error("表名信息异常");
                return result;
            }
            DataBaseTable dataBaseTable = dataBaseTableList.get(0);
            PageData pageData = new PageData(dataBaseTable, genConfig);
            HashMap<String, String> extendParams = new HashMap<>(16);
            extendParams.put("apiPackage", pageData.getApiPackage());
            extendParams.put("bussiPackage", pageData.getBussPackage());
            extendParams.put("author", pageData.getAuthor());
            extendParams.put("tablePrefix", pageData.getTablePrefix());

            TableVo tableVo = new TableVo();
            tableVo.setEntityName(dataBaseTable.getEntityNameHump());
            tableVo.setEntityPackage(dataBaseTable.getEntityPackage());
            tableVo.setFtlDescription("");
            tableVo.setTableName(tableName);
            tableVo.setSearchFieldNum(-1);
            tableVo.setExtendParams(null);

            CodeGeneratorEnum var8 = CodeGeneratorEnum.EMPTY;
            SystemCodeGenerateOne systemCodeGenerateOne = new SystemCodeGenerateOne(tableVo, new ArrayList<>(), new ArrayList<>(), extendParams);
            try {
                List<String> var9 = systemCodeGenerateOne.generateCodeFile(outFilePath, var8.getTemplatePath(), var8.getStylePath());
            } catch (Exception e) {
                e.printStackTrace();
                result.error(tableName + "生成失败");
                return result;
            }
        }
        return result;
    }


    public List<String> generateOneToMany(d model, CodeGeneratorEnum codeGeneratorEnum, HashMap<String, String> extendParams) throws Exception {
        MainTableVo var2 = new MainTableVo();
        var2.setEntityName(model.getEntityName());
        var2.setEntityPackage(model.getEntityPackage());
        var2.setFtlDescription(model.getFtlDescription());
        var2.setTableName(model.getTableName());
        LambdaQueryWrapper<OnlCgformHead> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OnlCgformHead::getId, model.getCode());
        OnlCgformHead var3 = onlCgformHeadService.getOne(queryWrapper);
        String var4 = var3.getFormTemplate();
        if (oConvertUtils.isEmpty(var4)) {
            var2.setFieldRowNum(1);
        } else {
            var2.setFieldRowNum(Integer.parseInt(var4));
        }

        ArrayList var5 = new ArrayList();
        ArrayList var6 = new ArrayList();
        this.a(model.getCode(), var5, var6);
        List var7 = model.getSubList();
        ArrayList var8 = new ArrayList();
        Iterator var9 = var7.iterator();

        while (var9.hasNext()) {
            d var10 = (d) var9.next();
            LambdaQueryWrapper<OnlCgformHead> queryWrapper1 = new LambdaQueryWrapper<>();
            queryWrapper1.eq(OnlCgformHead::getTableName, var10.getTableName());
            OnlCgformHead var11 = onlCgformHeadService.getOne(queryWrapper1);
            if (var11 != null) {
                SubTableVo var12 = new SubTableVo();
                var12.setEntityName(var10.getEntityName());
                var12.setEntityPackage(model.getEntityPackage());
                var12.setTableName(var10.getTableName());
                var12.setFtlDescription(var10.getFtlDescription());
                Integer var13 = var11.getRelationType();
                var12.setForeignRelationType(var13 == 1 ? "1" : "0");
                ArrayList var14 = new ArrayList();
                ArrayList var15 = new ArrayList();
                OnlCgformField var16 = this.a(var11.getId(), var14, var15);
                if (var16 != null) {
                    var12.setOriginalForeignKeys(new String[]{var16.getDbFieldName()});
                    var12.setForeignKeys(new String[]{var16.getDbFieldName()});
                    var12.setColums(var14);
                    var12.setOriginalColumns(var15);
                    var8.add(var12);
                }
            }
        }

        SystemCodeGenerateOneToMany generateOneToMany = new SystemCodeGenerateOneToMany(var2, var5, var6, var8, extendParams);
        List var18 = generateOneToMany.generateCodeFile(model.getProjectPath(), codeGeneratorEnum.getTemplatePath(), codeGeneratorEnum.getStylePath());
        return var18;
    }

    /**
     * 单表代码生成
     *
     * @param model 表信息
     * @return 生成结果
     * @throws Exception 生成异常
     */
    private SeedMessageDTO generateCode(d model, CodeGeneratorEnum codeGeneratorEnum, HashMap<String, String> extendParams) throws Exception {
        SeedMessageDTO result = new SeedMessageDTO();
        TableVo var2 = new TableVo();
        var2.setEntityName(model.getEntityName());
        var2.setEntityPackage(model.getEntityPackage());
        var2.setFtlDescription(model.getFtlDescription());
        var2.setTableName(model.getTableName());
        var2.setSearchFieldNum(-1);
        List<ColumnVo> var3 = new ArrayList<>();
        List<ColumnVo> var4 = new ArrayList<>();
        this.a(model.getCode(), var3, var4);
        LambdaQueryWrapper<OnlCgformHead> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OnlCgformHead::getId, model.getCode());
        OnlCgformHead var5 = onlCgformHeadService.getOne(queryWrapper);
        HashMap<String, String> var6 = new HashMap<>();
        var6.put("scroll", var5.getScroll() == null ? "0" : var5.getScroll().toString());
        String var7 = var5.getFormTemplate();
        if (oConvertUtils.isEmpty(var7)) {
            var2.setFieldRowNum(1);
        } else {
            var2.setFieldRowNum(Integer.parseInt(var7));
        }

        if ("Y".equals(var5.getIsTree())) {
            var6.put("pidField", var5.getTreeParentIdField());
            var6.put("hasChildren", var5.getTreeIdField());
            var6.put("textField", var5.getTreeFieldname());
        }

        var2.setExtendParams(var6);
        SystemCodeGenerateOne systemCodeGenerateOne = new SystemCodeGenerateOne(var2, var3, var4, extendParams);
        List<String> var9 = systemCodeGenerateOne.generateCodeFile(model.getProjectPath(), codeGeneratorEnum.getTemplatePath(), codeGeneratorEnum.getStylePath());

        return result;
    }


    private OnlCgformField a(String var1, List<ColumnVo> var2, List<ColumnVo> var3) {
        LambdaQueryWrapper<OnlCgformField> var4 = new LambdaQueryWrapper<>();
        var4.eq(OnlCgformField::getCgformHeadId, var1);
        var4.orderByAsc(OnlCgformField::getOrderNum);
        List var5 = this.fieldService.list(var4);
        OnlCgformField var6 = null;
        Iterator var7 = var5.iterator();

        while (true) {
            OnlCgformField var8;
            ColumnVo var9;
            do {
                if (!var7.hasNext()) {
                    return var6;
                }

                var8 = (OnlCgformField) var7.next();
                if (oConvertUtils.isNotEmpty(var8.getMainTable())) {
                    var6 = var8;
                }

                var9 = new ColumnVo();
                var9.setFieldLength(var8.getFieldLength());
                var9.setFieldHref(var8.getFieldHref());
                var9.setFieldValidType(var8.getFieldValidType());
                var9.setFieldDefault(var8.getDbDefaultVal());
                var9.setFieldShowType(var8.getFieldShowType());
                var9.setFieldOrderNum(var8.getOrderNum());
                var9.setIsKey(var8.getDbIsKey() == 1 ? "Y" : "N");
                var9.setIsShow(var8.getIsShowForm() == 1 ? "Y" : "N");
                var9.setIsShowList(var8.getIsShowList() == 1 ? "Y" : "N");
                var9.setIsQuery(var8.getIsQuery() == 1 ? "Y" : "N");
                var9.setQueryMode(var8.getQueryMode());
                var9.setDictField(var8.getDictField());
                if (oConvertUtils.isNotEmpty(var8.getDictTable()) && var8.getDictTable().indexOf("where") > 0) {
                    var9.setDictTable(var8.getDictTable().split("where")[0].trim());
                } else {
                    var9.setDictTable(var8.getDictTable());
                }

                var9.setDictText(var8.getDictText());
                var9.setFieldDbName(var8.getDbFieldName());
                var9.setFieldName(oConvertUtils.camelName(var8.getDbFieldName()));
                var9.setFiledComment(var8.getDbFieldTxt());
                var9.setFieldDbType(var8.getDbType());
                var9.setFieldType(this.a(var8.getDbType()));
                var9.setClassType(var8.getFieldShowType());
                var9.setClassType_row(var8.getFieldShowType());
                if (var8.getDbIsNull() != 0 && !"*".equals(var8.getFieldValidType()) && !"1".equals(var8.getFieldMustInput())) {
                    var9.setNullable("Y");
                } else {
                    var9.setNullable("N");
                }

                if ("switch".equals(var8.getFieldShowType())) {
                    var9.setDictField(var8.getFieldExtendJson());
                }

                var9.setSort("1".equals(var8.getSortFlag()) ? "Y" : "N");
                var9.setReadonly(Integer.valueOf(1).equals(var8.getIsReadOnly()) ? "Y" : "N");
                if (oConvertUtils.isNotEmpty(var8.getFieldDefaultValue())) {
                    var9.setDefaultVal(var8.getFieldDefaultValue());
                }

                if (("file".equals(var8.getFieldShowType()) || "image".equals(var8.getFieldShowType())) && oConvertUtils.isNotEmpty(var8.getFieldExtendJson())) {
                    JSONObject var10 = JSONObject.parseObject(var8.getFieldExtendJson());
                    if (oConvertUtils.isNotEmpty(var10.getString("uploadnum"))) {
                        var9.setUploadnum(var10.getString("uploadnum"));
                    }
                }

                var3.add(var9);
            } while (var8.getIsShowForm() != 1 && var8.getIsShowList() != 1);

            var2.add(var9);
        }
    }

    private String a(String var1) {
        var1 = var1.toLowerCase();
        if (var1.indexOf("int") >= 0) {
            return "java.lang.Integer";
        } else if (var1.indexOf("double") >= 0) {
            return "java.lang.Double";
        } else if (var1.indexOf("decimal") >= 0) {
            return "java.math.BigDecimal";
        } else {
            return var1.indexOf("date") >= 0 ? "java.util.Date" : "java.lang.String";
        }
    }
}
